﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections;
using JAAF.Collections;

namespace JAAF.UI
{
    /// <summary>
    /// This class is responsible for:
    /// The activation and navigation between the elements of the user interfece.
    /// Maintaining the state of the whole process, making it available to the user interface elements
    /// and notifying them of changes performed on this state.
    /// This is the base class from which all the user interface process classes should
    /// be derived.
    /// </summary>
    public abstract class UIProcess: INotifyPropertyChanged, ICustomTypeDescriptor
    {
        #region Instance data

        /// <summary>
        /// The <see cref="UIApplication">application</see> this process runs on.
        /// </summary>
        UIApplication m_oApplication;

        /// <summary>
        /// A string that idientifies this user inteface process
        /// </summary>
        private string m_sName;

        /// <summary>
        /// The process that started this as a child process.
        /// </summary>
        private UIProcess m_oParentProcess;

        /// <summary>
        /// The view that is currently activated.
        /// </summary>
        private IView m_oActiveView;

        /// <summary>
        /// Contains the views that are currently displayed
        /// by this process.
        /// </summary>
        //private List<IView> m_lstActiveViews;
        private ViewDictionary m_lstActiveViews;
        private ReadOnlyKeyedCollection<string, IView> m_lstActiveViewsRO;

        /// <summary>
        /// Remember in whare viewspace the views are displayed
        /// </summary>
        private Dictionary<IView, string> m_dicViewspaces;

        /// <summary>
        /// A reference to the child process that currently has the focus.
        /// </summary>
        private UIProcess m_oActiveChildProcess;

        /// <summary>
        /// Maintains a list with the child processes that have been started by this
        /// process.
        /// </summary>
        private List<UIProcess> m_lstChildProcesses;
        private ReadOnlyCollection<UIProcess> m_lstChildProcessesRO;


        private bool m_bStateInitialized;

        /// <summary>
        /// Maintains the state of this process
        /// </summary>
        private UIProcessState m_colState;

        #endregion


        #region Events

        /// <summary>
        /// An event that is fired after an element of the <see cref="UIProcess.State">state</see>
        /// of this process has been changed
        /// </summary>
        public event EventHandler<UIProcessStateChangedEventArgs> StateChanged;


        internal void OnStateChangedTrigger(string _sElementName, object _oOldValue)
        {
            if (!m_bStateInitialized)
                return;

            this.OnStateChanged(_sElementName, _oOldValue);
        }

        /// <summary>
        /// Notifies derived classes that a property of this process state
        /// has changed and fires the <see cref="UIProcess.SateChanged"/> event.
        /// This method also fires the <see cref="INotifyPropertyChanged.PropertyChanged"/> event.
        /// </summary>
        /// <param name="_sElementName">The name of the element of the state that has changed.</param>
        /// <param name="_oOldValue">The old value of the state element.</param>
        protected internal virtual void OnStateChanged(string _sElementName, object _oOldValue)
        {
            if (this.StateChanged != null)
            {
                UIProcessStateChangedEventArgs oArgs = new UIProcessStateChangedEventArgs(_sElementName, _oOldValue);
                this.StateChanged(this, oArgs);
            }

            if (m_dlgPropertyChanged != null)
            {
                m_dlgPropertyChanged(this, new PropertyChangedEventArgs(_sElementName));
            }            
        }


        //
        // INotifyPropertyChanged Implementation
        //

        private PropertyChangedEventHandler m_dlgPropertyChanged;

        event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
        {
            add { m_dlgPropertyChanged += value; }

            remove { m_dlgPropertyChanged -= value; }
        }

        // --------------------------------------------------


        /// <summary>
        /// An event that is fired when the <see cref="UIProcess"/> stops.
        /// </summary>
        public event EventHandler Stopped;

        /// <summary>
        /// Fires the <see cref="UIProcess.Stopped"/> event.
        /// </summary>
        protected virtual void OnStopped()
        {
            if (this.Stopped != null)
                this.Stopped(this, EventArgs.Empty);
        }


        #endregion


        #region Initialization

        /// <summary>
        /// Creates an instance of the user interface process.
        /// </summary>
        /// <param name="_oApplication">The application that owns the process</param>
        protected UIProcess(UIApplication _oApplication)
        {
            if (_oApplication == null)
                throw new ArgumentNullException("_oApplication");

            m_oApplication = _oApplication;

            //m_lstActiveViews = new List<IView>();
            m_lstActiveViews = new ViewDictionary();
            m_lstActiveViewsRO = m_lstActiveViews.AsReadOnly();
            m_dicViewspaces = new Dictionary<IView, string>();

            m_lstChildProcesses = new List<UIProcess>();
            m_lstChildProcessesRO = m_lstChildProcesses.AsReadOnly();

            m_colState = new UIProcessState(this);

            this._InitializeCommands();

            this.Status = UIProcessStatusEnum.Initialized;
        }




        #endregion


        #region Properties

        /// <summary>
        /// Gets the <see cref="UIApplication"/> instance under which this process is executing
        /// </summary>
        public UIApplication Application
        {
            get
            {
                return m_oApplication;
            }
        }

        /// <summary>
        /// Gets or sets a string that identifies this particular user interface process
        /// </summary>
        public string Name
        {
            get
            {
                if (m_sName == null)
                    return this.GetType().FullName;
                else
                    return m_sName;
            }

            set
            {
                m_sName = value;
            }
        }

        /// <summary>
        /// Gets the current <see cref="UIProcStatusEnum">status</see> of the user
        /// interface process.
        /// </summary>
        public UIProcessStatusEnum Status
        {
            get;

            protected set;
        }

        /// <summary>
        /// Indicates that this process is no longer executing and has either been aborted or completed.
        /// </summary>
        public bool IsStopped
        {
            get
            {
                return (this.Status == UIProcessStatusEnum.Aborted || this.Status == UIProcessStatusEnum.Completed);
            }
        }

        /// <summary>
        /// A list of the <see cref="IView">views</see> that are
        /// currenlty displayed by this process.
        /// </summary>
        public ReadOnlyKeyedCollection<string, IView> Views
        {
            get
            {
                return m_lstActiveViewsRO;
            }
        }

        /// <summary>
        /// Gets the <see cref="IView">view</see> that currently has the focus
        /// </summary>
        public IView ActiveView
        {
            get
            {
                return m_oActiveView;
            }
        }

        /// <summary>
        /// Gets the <see cref="UIProcess">process</see> under which this one is executing.
        /// </summary>
        public UIProcess ParentProcess
        {
            get
            {
                return m_oParentProcess;
            }

            private set
            {
                m_oParentProcess = value;
            }
        }

        #endregion


        #region Navigation

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_oParentProcess"></param>
        public void Start()
        {
            if (this.Status != UIProcessStatusEnum.Initialized)
                throw new InvalidOperationException("The user interface process {0} cannot be started becaus it is not in an appropriate state");

            this._InitializeState();
            this.OnStart();
            this.Status = UIProcessStatusEnum.Executing;
        }

        public abstract void OnStart();

        public virtual bool CanComplete()
        {
            if (this.Application.Status == UIApplicationStatusEnum.ShuttingDown)
                return false;

            if (m_lstChildProcesses.Any(oChild => !oChild.CanComplete()))
                return false;

            if (this.Status == UIProcessStatusEnum.Aborting
                || this.IsStopped
                || this.Status == UIProcessStatusEnum.ResumingFromChildProc)
            {
                return false;
            }

            return true;
        }

        public void Complete()
        {
            if (!this.CanComplete())
                return;

            UIProcessStatusEnum eBackupStatus = this.Status;
            this.Status = UIProcessStatusEnum.Completing;

            try
            {
                this.OnCompleting();
            }
            catch (Exception exc)
            {
                this.Status = eBackupStatus;
                this.Application.DisplayException(exc);
                this.Status = eBackupStatus;
                return;
            }

            this._CloseAllViews();

            this.Status = UIProcessStatusEnum.Completed;
            this.OnCompleted();

            this.OnStopped();

            if (m_oParentProcess != null)
                m_oParentProcess._ResumeFromChild(this);
        }

        public virtual void OnCompleting()
        {

        }

        public virtual void OnCompleted()
        {

        }

        public virtual bool CanAbort()
        {
            if (this.Application.Status != UIApplicationStatusEnum.ShuttingDown
                && m_lstChildProcesses.Any(oChild => !oChild.CanAbort()))
            {
                return false;
            }

            if (this.Status == UIProcessStatusEnum.Completing
                || this.Status == UIProcessStatusEnum.Aborting
                || this.IsStopped)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Stops the user interface process, closes all it's active <see cref="IView">views</see>
        /// and sets it's <see cref="UIProcess.Status">state</see> to <see cref="UIProcessStatusEnum.Aborted"/>.
        /// </summary>
        /// <remarks>
        /// Calling this method signifies a failure or abortion of the execution of the user interface process.
        /// The <see cref="UIProcess.State">state</see> should be considered invalid after the Abort
        /// method is called, unless it carries information specific to the abortion.
        /// </remarks>
        public void Abort()
        {
            if (this.Application.Status != UIApplicationStatusEnum.ShuttingDown
                && this.CanAbort() == false)
            {
                return;
            }

            this.Status = UIProcessStatusEnum.Aborting;
            this.OnAborting();

            foreach (UIProcess oChildProc in m_lstChildProcesses.ToArray())
            {
                oChildProc.Abort();
            }

            this._CloseAllViews();

            this.Status = UIProcessStatusEnum.Aborted;
            this.OnAborted();

            this.OnStopped();

            if (m_oParentProcess != null)
                m_oParentProcess._ResumeFromChild(this);
        }

        protected virtual void OnAborting()
        {

        }

        protected virtual void OnAborted()
        {

        }

        #endregion


        #region Child process management


        /// <summary>
        /// Begins a child user interface process that will execute within the context
        /// of this process.
        /// </summary>
        /// <param name="_oChildProc">The process to start as a child under this process.</param>
        /// <param name="a_bStartModal"> 
        /// If true the parent process user interface will be suspended 
        /// during the execution of this new child process.
        /// </param>
        public void StartChildProcess(UIProcess _oChildProc, bool _bStartModal = false)
        {
            lock (m_lstChildProcesses)
            {
                if (m_lstChildProcesses.Contains(_oChildProc))
                    return;

                m_lstChildProcesses.Add(_oChildProc);
                _oChildProc.ParentProcess = this;

                this.OnChildProcessStarting(_oChildProc);
                _oChildProc.Start();
                this.OnChildProcessStarted(_oChildProc);
            }
        }

        /// <summary>
        /// This method is called just before a child <see cref="UIProcess">process</see> is started 
        /// by this <see cref="UIProcess">process</see>.
        /// </summary>
        /// <param name="_oChildProcess">The child <see cref="UIProcess">process</see> that is about to be started</param>
        protected virtual void OnChildProcessStarting(UIProcess _oChildProcess)
        {

        }

        /// <summary>
        /// This method is called after a child <see cref="UIProcess">process</see> is started
        /// by this <see cref="UIProcess">process</see>.
        /// </summary>
        /// <param name="_oChildProcess">The child <see cref="UIProcess">process</see> that has been started.</param>
        protected virtual void OnChildProcessStarted(UIProcess _oChildProcess)
        {

        }

        /// <summary>
        /// This method is called by every child process that has been started by this when it ends
        /// </summary>
        /// <param name="_oChildProcess">The child process that made the call.</param>
        private void _ResumeFromChild(UIProcess _oChildProcess)
        {
            lock (m_lstChildProcesses)
            {
                if (!m_lstChildProcesses.Contains(_oChildProcess))
                    return;

                m_lstChildProcesses.Remove(_oChildProcess);

                string sViewspaceName;

                foreach (IView oView in m_lstActiveViews)
                {
                    sViewspaceName = m_dicViewspaces[oView];
                    this.DisplayView(oView, sViewspaceName);
                }

                if (_oChildProcess.Status == UIProcessStatusEnum.Completed)
                    this.OnChildProcessCompleted(_oChildProcess);
                else if (_oChildProcess.Status == UIProcessStatusEnum.Aborted)
                    this.OnChildProcessAborted(_oChildProcess);

                this.OnChildProcessStopped(_oChildProcess);
            }
        }

        /// <summary>
        /// This method is called after a child <see cref="UIProcess">process</see> that
        /// has been started by this <see cref="UIProcess"> has completed succesfully.
        /// </summary>
        /// <param name="_oChildProcess">The child <see cref="UIProcess">process</see> that has stopped.</param>
        protected virtual void OnChildProcessCompleted(UIProcess _oChildProcess)
        {

        }

        /// <summary>
        /// This method is called after a child <see cref="UIProcess">process</see> that
        /// has been started by this <see cref="UIProcess"> has been aborted.
        /// </summary>
        /// <param name="_oChildProcess">The child <see cref="UIProcess">process</see> that has stopped.</param>
        protected virtual void OnChildProcessAborted(UIProcess _oChildProcess)
        {

        }

        /// <summary>
        /// This method is called after a child <see cref="UIProcess">process</see> that
        /// has been started by this <see cref="UIProcess"> has stopped
        /// </summary>
        /// <param name="_oChildProcess">The child <see cref="UIProcess">process</see> that has stopped.</param>
        protected virtual void OnChildProcessStopped(UIProcess _oChildProcess)
        {

        }

        #endregion


        #region State management

        /// <summary>
        /// Provides access to the <see cref="T:UIProcessState">state</see> of this process.
        /// </summary>
        public UIProcessState State
        {
            get
            {
                return m_colState;
            }
        }

        /// <summary>
        /// Performs the internal state initialization
        /// </summary>
        private void _InitializeState()
        {
            if (m_bStateInitialized)
                return;

            // Initialize the state of this process
            if (m_oParentProcess != null)
            {
                m_colState.Combine(m_oParentProcess.State);
            }
            
            this.InitializeState();
            m_bStateInitialized = true;
        }

        /// <summary>
        /// Derived types may override this method in order to add
        /// initial values to the <see cref="UIProcess.State">state</see>
        /// of the process.
        /// </summary>
        protected virtual void InitializeState()
        {
        }

        #endregion


        #region Command management

        private void _InitializeCommands()
        {
            this.CompleteCommand = new DelegateCommand(this._CompleteCommandHandler);
            this.AbortCommand = new DelegateCommand(this._AbortCommandHandler);
        }

        public virtual void ExecuteCommand(UIProcessCommand _oCommand, object _oParameter)
        {

        }

        public virtual bool CanExecuteCommand(UIProcessCommand _oCommand, object _oParameter)
        {
            return true;
        }

        public IUICommand CompleteCommand
        {
            get;

            private set;
        }

        private void _CompleteCommandHandler(object _oArgument)
        {
            this.Complete();
        }

        public IUICommand AbortCommand
        {
            get;

            private set;
        }

        private void _AbortCommandHandler(object _oArgument)
        {
            this.Abort();
        }

        #endregion


        #region View management

        /// <summary>
        /// Displays an allready instantiated <see cref="IView">view</see>.
        /// </summary>
        /// <param name="_oView">The <see cref="IView">view</see> to display</param>
        /// <param name="_sViewspaceName"></param>
        public void DisplayView(IView _oView, string _sViewspaceName = null)
        {
            IViewspace oTargetViewspace;

            if (_sViewspaceName == null)
                oTargetViewspace = this.Application.DefaultViewspace;
            else
                oTargetViewspace = this.Application.Viewspaces[_sViewspaceName];

            _oView.Initialize(this);
            oTargetViewspace.ShowView(_oView);

            lock (m_lstActiveViews)
            {
                if (!m_lstActiveViews.Contains(_oView))
                {
                    m_lstActiveViews.Add(_oView);
                }
            }

            m_dicViewspaces[_oView] = _sViewspaceName;

            m_oActiveView = _oView;
        }

        /// <summary>
        /// Creates and displays a view of a specified <paramref name="_oViewType"/>.
        /// </summary>
        /// <remarks>
        /// This 
        /// </remarks>
        /// <param name="_oViewType">
        /// The <see cref="System.Type"/> of the view that will be created and displayed.
        /// </param>
        /// <param name="_sViewspaceName">
        /// </param>
        /// <param name="_sTitle">
        /// </param>
        public void DisplayView(Type _oViewType, string _sViewspaceName = null, string _sTitle = null)
        {
            IView oView = (IView)this.Application.CreateView(_oViewType);
            
            if (_sTitle != null)
                oView.Title = _sTitle;

            this.DisplayView(oView, _sViewspaceName);
        }

        /// <summary>
        /// Creates and displays the <see cref="IView">view</see> with the provided name.
        /// The name of the view is used as an argument to the <see cref="UIApplication">application's</see>
        /// view builder.
        /// </summary>
        /// <remarks>
        /// Use this method when the type of the view is not known at design time. The type will be resolved
        /// at run-time using a <see cref="JAAF.Builders.BuilderBase">builder</see>(dependency injection container).
        /// The view name provided to this method should be registered in the Builders section in the application configuration file.
        /// </remarks>
        /// <param name="_sViewName">
        /// The name of the view to create and display. </param>
        /// <param name="_sViewspaceName">
        /// The name of the <see cref="IViewSpace">viewspace</see> inside which the view will be displayed.
        /// </param>
        public void DisplayView(string _sViewName, string _sViewspaceName = null, string _sTitle = null)
        {
            IView oView = (IView)this.Application.CreateView(_sViewName);

            if (!string.IsNullOrWhiteSpace(_sViewName))
                oView.Name = _sViewName;

            if (_sTitle != null)
                oView.Title = _sTitle;

            this.DisplayView(oView, _sViewspaceName);
        }

        /// <summary>
        /// Hides a <see cref="IView">view</see> that has been previously displayed by this process.
        /// </summary>
        /// <param name="_oView">The <see cref="IView">view</see> to hide.</param>
        public void HideView(IView _oView)
        {
            foreach (KeyValuePair<string, IViewspace> oViewspace in m_oApplication.Viewspaces)
            {
                if (oViewspace.Value.Views.ContainsValue(_oView))
                {
                    oViewspace.Value.HideView(_oView);
                    break;
                }
            }
        }

        /// <summary>
        /// Closes all the views displayed by this process.
        /// </summary>
        private void _CloseAllViews()
        {
            foreach (IView oView in m_lstActiveViews.ToArray())
            {
                this.CloseView(oView);
            }
        }

        public void CloseView(IView _oView)
        {
            lock (m_lstActiveViews)
            {
                if (!m_lstActiveViews.Contains(_oView))
                    return;

                _oView.Close();
                m_lstActiveViews.Remove(_oView);

                if (m_lstActiveViews.Count == 0
                    && this.Status != UIProcessStatusEnum.Aborting
                    && this.Status != UIProcessStatusEnum.Completing
                    && this.Status != UIProcessStatusEnum.Navigating
                    && this.CanComplete())
                {
                    this.Complete();
                }
            }
        }

        #endregion


        #region ICustomTypeDescriptor Implementation

        PropertyDescriptorCollection m_colPropDescriptors;


        /// <summary>
        /// Returns a collection of custom attributes for this instance of a component.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.ComponentModel.AttributeCollection"/> containing the attributes for this object.
        /// </returns>
        AttributeCollection ICustomTypeDescriptor.GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this.GetType());
        }

        /// <summary>
        /// Returns the class name of this instance of a component.
        /// </summary>
        /// <returns>
        /// The class name of the object, or null if the class does not have a name.
        /// </returns>
        string ICustomTypeDescriptor.GetClassName()
        {
            return TypeDescriptor.GetClassName(this.GetType());
        }

        /// <summary>
        /// Returns the name of this instance of a component.
        /// </summary>
        /// <returns>
        /// The name of the object, or null if the object does not have a name.
        /// </returns>
        string ICustomTypeDescriptor.GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this.GetType());
        }

        /// <summary>
        /// Returns a type converter for this instance of a component.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.ComponentModel.TypeConverter"/> that is the converter for this object, or null if there is no <see cref="T:System.ComponentModel.TypeConverter"/> for this object.
        /// </returns>
        TypeConverter ICustomTypeDescriptor.GetConverter()
        {
            return TypeDescriptor.GetConverter(this.GetType());
        }

        /// <summary>
        /// Returns the default event for this instance of a component.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.ComponentModel.EventDescriptor"/> that represents the default event for this object, or null if this object does not have events.
        /// </returns>
        EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this.GetType());
        }

        /// <summary>
        /// Returns the default property for this instance of a component.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.ComponentModel.PropertyDescriptor"/> that represents the default property for this object, or null if this object does not have properties.
        /// </returns>
        PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
        {
            return TypeDescriptor.GetDefaultProperty(this.GetType());
        }

        /// <summary>
        /// Returns an editor of the specified type for this instance of a component.
        /// </summary>
        /// <param name="editorBaseType">A <see cref="T:System.Type"/> that represents the editor for this object.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> of the specified type that is the editor for this object, or null if the editor cannot be found.
        /// </returns>
        object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
        {
            return null;
        }

        /// <summary>
        /// Returns the events for this instance of a component using the specified attribute array as a filter.
        /// </summary>
        /// <param name="attributes">An array of type <see cref="T:System.Attribute"/> that is used as a filter.</param>
        /// <returns>
        /// An <see cref="T:System.ComponentModel.EventDescriptorCollection"/> that represents the filtered events for this component instance.
        /// </returns>
        EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this.GetType(), attributes);
        }

        /// <summary>
        /// Returns the events for this instance of a component.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.ComponentModel.EventDescriptorCollection"/> that represents the events for this component instance.
        /// </returns>
        EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
        {
            return TypeDescriptor.GetEvents(this.GetType());
        }

        /// <summary>
        /// Returns the properties for this instance of a component using the attribute array as a filter.
        /// </summary>
        /// <param name="attributes">An array of type <see cref="T:System.Attribute"/> that is used as a filter.</param>
        /// <returns>
        /// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection"/> that represents the filtered properties for this component instance.
        /// </returns>
        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
        {
            if (m_colPropDescriptors == null)
            {
                PropertyDescriptorCollection colBaseProperties = TypeDescriptor.GetProperties(this.GetType(), attributes);
                PropertyDescriptor[] aoBaseProps = new PropertyDescriptor[colBaseProperties.Count];
                colBaseProperties.CopyTo(aoBaseProps, 0);
                PropertyDescriptorCollection colCombinedProps = new PropertyDescriptorCollection(aoBaseProps, false);

                var qVisibleElements = from StateElement e in this.State 
                                       where e.AccessLevel != StateElementAccessLevelEnum.None 
                                       select e;
                
                foreach (StateElement oElm in qVisibleElements)
                {
                    colCombinedProps.Add(new StateElementPropertyDescriptor(this, oElm));
                }

                m_colPropDescriptors = colCombinedProps;
            }

            return m_colPropDescriptors;
        }

        /// <summary>
        /// Returns the properties for this instance of a component.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection"/> that represents the properties for this component instance.
        /// </returns>
        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        {
            return ((ICustomTypeDescriptor)this).GetProperties(null);
        }

        /// <summary>
        /// Returns an object that contains the property described by the specified property descriptor.
        /// </summary>
        /// <param name="pd">A <see cref="T:System.ComponentModel.PropertyDescriptor"/> that represents the property whose owner is to be found.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> that represents the owner of the specified property.
        /// </returns>
        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        #endregion

    }
}
